package com.xyrl.third.aliyun.service;

import cn.hutool.json.JSONUtil;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * Copyright © 2018 重庆大鼎科技有限公司. All rights reserved.
 *
 * @Title: OssBucketService.java
 * @Prject: common-oss
 * @Package: com.dading.common.oss
 * @Description: 对oss中的存储的命名空间进行管理(添加 、 删除 、 查看, 权限管理)
 * @author: 黄胜明
 * @date: 2018年5月17日 下午5:12:52
 * @version: V1.0
 */
@Slf4j
public class OssBucketService {

    private OSS oss;

    public void setOssClient(OSS oss) {
        this.oss = oss;
    }

    /****
     * @Title: createBucket
     * @Description:
     *   新建命名空间：全局变量，名字必须唯一，重复则创建失败，相当于一个虚拟的文件夹
     * @param bucketName  命名空间
     * <ol style="color:red;">
     *  <li>只能包括小写字母，数字，短横线（-）</li>
     *  <li>必须以小写字母或者数字开头</li>
     *  <li>长度必须在3-63字节之间</li>
     * </ol>
     * @param eStorageClass  存储类型(枚举类型)
     * <ol style="color:red;">
     *  <li>Standard:标准存储类型（Standard）
     *    提供高可靠、高可用、高性能的对象存储服务，能够支持频繁的数据访问。OSS高吞吐和低延时的服务响应能力能够有效支持各种热点类型数据的访问。
     *    标准存储类型是各种社交、分享类的图片、音视频应用、大型网站、大数据分析的合适选择。
     *  </li>
     *  <li>IA:低频访问存储类型（Infrequent Access）
     *    适合长期保存不经常访问的数据，存储单价低于标准类型，适合各类移动应用、智能设备、企业数据的长期备份。低频访问存储类型的Object有最短存储时间，存储时间短于30天的文件提前删除会产生一定费用。
     *    低频访问存储Object有最小计量空间，Object大小低于64KB，会按照64KB计算存储空间，数据获取会产生费用。
     *  </li>
     *  <li>Archive:归档存储类型（Archive）
     *    单价最低，适合需要长期保存（建议半年以上）的归档数据，在存储周期内极少被访问，数据进入到可读取状态需要等待1分钟的解冻时间。适合需要长期保存的档案数据、医疗影像、科学资料、影视素材。
     *    归档存储类型的Object有最短存储时间，存储时间短于60天的文件提前删除会产生一定费用。归档类型存储Object有最小计量空间，Object大小低于64KB，会按照64KB计算存储空间，数据获取会产生费用。
     *  </li>
     * </ol>
     * @param eCannedAccessControl  操作权限(枚举类型)
     * <ol style="color:red;">
     *  <li>public-read-write: 任何人（包括匿名访问）都可以对该bucket中的object进行上传、下载和删除操作；所有这些操作产生的费用由该bucket的创建者承担，请慎用该权限。</li>
     *  <li>public-read: 只有该bucket的创建者可以对该bucket内的Object进行写操作（包括上传和删除）；任何人（包括匿名访问）可以对该bucket中的object进行读操作。</li>
     *  <li>private: 只有该bucket的创建者才可以访问此Bukcet。其他人禁止对此Bucket做任何操作。</li>
     * <ol>
     * @return: boolean
     * @author: 黄胜明
     * @date: 2018年5月17日 下午2:53:09
     * @version: V1.0
     */
    public boolean createBucket(String bucketName, StorageClass eStorageClass, CannedAccessControlList eCannedAccessControl) {
        try {
            if (!existBucket(bucketName)) {
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                // 设置bucket权限为公共读，默认是私有读写
                createBucketRequest.setCannedACL(eCannedAccessControl);
                // 设置bucket存储类型为低频访问类型，默认是标准类型
                createBucketRequest.setStorageClass(eStorageClass);
                oss.createBucket(createBucketRequest);
                return true;
            }
            throw new OSSException(bucketName + " is exist !!!");
        } catch (OSSException e) {
            log.error("create bucket error::", e);
        } catch (ClientException e) {
            log.error("OSS connection error::", e);
        }
        return false;
    }

    /****
     *
     * @Title: createBucket
     * @Description:
     *   新建命名空间：全局变量，名字必须唯一，重复则创建失败，相当于一个虚拟的文件夹
     * @param bucketName  命名空间
     * <ol style="color:red;">
     *  <li>只能包括小写字母，数字，短横线（-）</li>
     *  <li>必须以小写字母或者数字开头</li>
     *  <li>长度必须在3-63字节之间</li>
     * </ol>
     * @param eCannedAccessControl  操作权限(枚举类型)
     * <ol style="color:red;">
     *  <li>public-read-write: 任何人（包括匿名访问）都可以对该bucket中的object进行上传、下载和删除操作；所有这些操作产生的费用由该bucket的创建者承担，请慎用该权限。</li>
     *  <li>public-read: 只有该bucket的创建者可以对该bucket内的Object进行写操作（包括上传和删除）；任何人（包括匿名访问）可以对该bucket中的object进行读操作。</li>
     *  <li>private: 只有该bucket的创建者才可以访问此Bukcet。其他人禁止对此Bucket做任何操作。</li>
     * <ol>
     * @return: boolean
     * @author: 黄胜明
     * @date: 2018年5月17日 下午2:53:09
     * @version: V1.0
     */
    public boolean createBucket(String bucketName, CannedAccessControlList eCannedAccessControl) {
        try {
            if (!existBucket(bucketName)) {
                CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
                // 设置bucket权限为公共读，默认是私有读写
                createBucketRequest.setCannedACL(eCannedAccessControl);
                // 设置bucket存储类型为低频访问类型，默认是标准类型
                createBucketRequest.setStorageClass(StorageClass.Standard);
                oss.createBucket(createBucketRequest);
                return true;
            }
            throw new OSSException(bucketName + " is exist !!!");
        } catch (OSSException e) {
            log.error("create bucket error::", e);
        } catch (ClientException e) {
            log.error("OSS connection error::", e);
        }
        return false;
    }

    /***
     *
     * @Title: updateBucketAcl
     * @Description:
     *  修改命名空间访问权限
     * @param bucketName 命名空间名称
     * @param eCannedAccessControl  操作权限(枚举类型)
     * <ol style="color:red;">
     *  <li>public-read-write: 任何人（包括匿名访问）都可以对该bucket中的object进行上传、下载和删除操作；所有这些操作产生的费用由该bucket的创建者承担，请慎用该权限。</li>
     *  <li>public-read: 只有该bucket的创建者可以对该bucket内的Object进行写操作（包括上传和删除）；任何人（包括匿名访问）可以对该bucket中的object进行读操作。</li>
     *  <li>private: 只有该bucket的创建者才可以访问此Bukcet。其他人禁止对此Bucket做任何操作。</li>
     * <ol>
     * @return
     * @return: boolean
     * @author: 黄胜明
     * @date: 2018年5月18日 上午10:57:10
     * @version: V1.0
     */
    public boolean updateBucketAcl(String bucketName, CannedAccessControlList eCannedAccessControl) {
        try {
            if (existBucket(bucketName)) {
                oss.setBucketAcl(bucketName, eCannedAccessControl);
                return true;
            }
            throw new OSSException(bucketName + " is not exist !!!");
        } catch (OSSException e) {
            log.error("create bucket error::", e);
        } catch (ClientException e) {
            log.error("OSS connection error::", e);
        }
        return false;
    }

    /****
     *
     * @Title: listbucket
     * @Description: 遍历用户所有的Bucket
     * @return
     * @return: List<Bucket>
     * @author: 黄胜明
     * @date: 2018年5月17日 下午3:09:27
     * @version: V1.0
     */
    public List<Bucket> listbucket() {
        List<Bucket> buckets = oss.listBuckets();
        return buckets;
    }

    /****
     *
     * @Title: getBucketInfo
     * @Description: 获取指定命名空间的详细信息(Location 、 CreationDate 、 Owner及权限等信息)
     * @param bucketName
     * @return
     * @return: List<Bucket>
     * @author: 黄胜明
     * @date: 2018年5月18日 上午11:04:11
     * @version: V1.0
     */
    public BucketInfo getBucketInfo(String bucketName) {
        if (!existBucket(bucketName)) {
            return null;
        }
        BucketInfo info = oss.getBucketInfo(bucketName);
        log.info(bucketName + " info::{}", JSONUtil.parse(info));
        return info;
    }

    /***
     *
     * @Title: deleteBucket
     * @Description: 删除bucket，如果此bucket有object,需要先删除所有其下的Object，否则无法删除
     * @param bucketName
     * @return
     * @return: boolean
     * @author: 黄胜明
     * @date: 2018年5月17日 下午2:51:09
     * @version: V1.0
     */
    public boolean deleteBucket(String bucketName) {
        try {
            boolean exists = oss.doesBucketExist(bucketName);
            if (exists) {
                ObjectListing objects = oss.listObjects(bucketName);
                for (OSSObjectSummary objectSummary : objects.getObjectSummaries()) {
                    oss.deleteObject(bucketName, objectSummary.getKey());
                }
                oss.deleteBucket(bucketName);
                return true;
            }
            throw new OSSException(bucketName + " is not exist !!!");
        } catch (OSSException e) {
            log.error("create bucket error::", e);
        } catch (ClientException e) {
            log.error("OSS connection error::", e);
        }
        return false;
    }

    /**
     * @param bucketName
     * @return
     * @Title: existBucket
     * @Description: 检查bucket是否存在
     * @return: boolean
     * @author: 黄胜明
     * @date: 2018年5月17日 下午2:52:08
     * @version: V1.0
     */
    public boolean existBucket(String bucketName) {
        boolean exists = oss.doesBucketExist(bucketName);
        if (exists) {
            log.info("Bucket exists");
            return true;
        } else {
            log.info("Bucket not exists");
            return false;
        }
    }

    /***
     *
     * @Title: getBucketLocation
     * @Description 根据存储空间名称获取到所在区域, 目前有效的数据中心如下：
     * <ol>
     *   <li>杭州数据中心: oss-cn-hangzhou</li>
     *   <li>青岛数据中心: oss-cn-qingdao</li>
     *   <li>北京数据中心: oss-cn-beijing</li>
     *   <li>香港数据中心: oss-cn-hongkong</li>
     *   <li>深圳数据中心: oss-cn-shenzhen</li>
     *   <li>上海数据中心: oss-cn-shanghai</li>
     *   <li>美国硅谷数据中心: oss-us-west-1</li>
     *   <li>美国弗吉尼亚数据中心: oss-us-east-1</li>
     *   <li>亚太（新加坡）数据中心: oss-ap-southeast-1</li>
     * </ol>
     * @param bucketName 存储空间名称
     * @return
     * @return: String
     * @author: 黄胜明
     * @date: 2018年5月21日 上午10:09:46
     * @version: V1.0
     */
    public String getBucketLocation(String bucketName) {
        return oss.getBucketLocation(bucketName);
    }
}
